﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;
using System.ServiceModel.Description;
using System.ServiceModel;

namespace DC.Serialization.Demo
{
    /*
     * 默认情况下, .NET 自定义类和结构不支持序列化. 若要指定类的实例支持序列化，可以在该类或结构的定义中使用SerialazableAttribute特性。
     * 序列化是通过各种各样的格式化器完成的。只有被标记为为Serializable的类或结构才能被格式化。     
     * 
     * 下面是一些自定义类：
     */

    [Serializable]
    public class Address
    {
        public string Country { get; set; }
        public string Province { get; set; }
        public string City { get; set; }
        public string Street { get; set; }
    }

    [Serializable]
    public class Contact
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string PhoneNumber { get; set; }
        public Address Address { get; set; }
    }

    [Serializable]
    public class Customer : Contact
    {
        public string Company { get; set; }
        public Contact Contact { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            //DemoSerializableFormatter();
            StartServiceHost();
        }

        private static void StartServiceHost()
        {
            using (ServiceHost host = new ServiceHost(typeof(DC.Serialization.Demo.Services), new Uri("http://localhost:8000/SerializableService/")))
            {
                if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
                {
                    ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
                    behavior.HttpGetEnabled = true;

                    behavior.HttpGetUrl = new Uri("http://localhost:8000/SerializableService/metadata");
                    host.Description.Behaviors.Add(behavior);
                }

                //Add Endpoint
                host.AddServiceEndpoint(typeof(DC.Serialization.Demo.IContract), new WSHttpBinding(), "");
                host.CloseTimeout = TimeSpan.FromSeconds(10);

                host.Open();
                Console.WriteLine("Host started");
                Console.ReadKey();
                host.Close();
            }
        }

        private static void DemoSerializableFormatter()
        {
            /*
             * 开始测试各种各样的格式化器
             * 1. .Net Formater
             * 2. WCF Formatter
             */

            //Create test object
            Contact contact = new Contact();
            contact.Address = new Address();
            contact.Address.City = "九江";
            contact.Address.Province = "江西";
            contact.PhoneNumber = "13816006002";

            /*
             * .Net Formater
             * 1. BinaryFormatter：将类型序列化为二进制格式，优点是速度快。
             * 2. SoapFormatter：将类型序列化为SOAP XML格式
             * 两种格式器都实现了IFormatter接口。它们除了要持久化对象状态，还要将类型的程序集，版本控制信息持久化到流中。这样才能保证序列化的对象能够反序列化为正确的类型。
             * 以上两种序列化器无法满足面向服务的互交，因为面向服务的互交方式要求其他的参与方与不仅拥有类型程序集，还要使用 .NET. 由于在某种程度上它要求客户端和服务端能共享流，因此也是无奈之举。
             */

            // 1. Demo BinaryFormatter
            using (System.IO.Stream stream = new System.IO.MemoryStream())
            {
                BinaryFormatter binaryFormatter = new BinaryFormatter();

                //Serializer: write object to stream by the formatter 
                binaryFormatter.Serialize(stream, contact);
                stream.Position = 0;

                //Deserializer
                Contact newContact = (Contact)binaryFormatter.Deserialize(stream);

                Console.WriteLine("BinaryFormatter");
                Console.WriteLine(newContact.Address.City);
                Console.WriteLine(newContact.PhoneNumber);
            }
            Console.WriteLine();

            // 2. Demo SoapFormatter
            using (System.IO.Stream stream = new System.IO.MemoryStream())
            {
                SoapFormatter soapFormatter = new SoapFormatter();

                //Serializer: write object to stream by the formatter 
                soapFormatter.Serialize(stream, contact);
                stream.Position = 0;

                //Deserializer
                Contact newContact = (Contact)soapFormatter.Deserialize(stream);

                Console.WriteLine("SoapFormatter");
                Console.WriteLine(newContact.Address.City);
                Console.WriteLine(newContact.PhoneNumber);
            }
            Console.WriteLine();

            /*
             * WCF Formatter
             * 1: DataContractSerializer  只能捕获对象状态，它并没有实现IFormatter接口。
             *      一般情况下WCF会自动选择使用DataContractSerializer，而不需要开发者直接
             *      调用。WCF会自动使用DataContractSerializer进行序列化与反序列化
             *      
             * 2. NetDataContractSerializer 格式化器，它是IFormatter接口的多态实现，
             *      因此与传统的.NET格式化器类似，除了获取对象状态外，还包括类型信息。
             *      NetDataContractSerializer有利于版本兼容，也利于将那些共享类型信息
             *      的旧代码迁移到更具面向服务特性的程序中。
             */

            //1. Demo DataContractSerializer
            using (System.IO.Stream stream = new System.IO.MemoryStream())
            {
                //Create DataContractSerializer formatter
                DataContractSerializer dcFormatter = new DataContractSerializer(typeof(Contact));

                //Serializer: write object to stream by the formatter 
                dcFormatter.WriteObject(stream, contact);
                stream.Position = 0;

                //Deserializer
                Contact newContact = (Contact)dcFormatter.ReadObject(stream);

                Console.WriteLine("DataContractSerializerFormatter");
                Console.WriteLine(newContact.Address.City);
                Console.WriteLine(newContact.PhoneNumber);
            }
            Console.WriteLine();

            //2. Demo NetDataContractSerializer
            using (System.IO.Stream stream = new System.IO.MemoryStream())
            {
                //Create NetDataContractSerializer formatter
                NetDataContractSerializer ndcFormatter = new NetDataContractSerializer();

                //Serializer: write object to stream by the formatter 
                ndcFormatter.WriteObject(stream, contact);
                stream.Position = 0;

                //Deserializer
                Contact newContact = (Contact)ndcFormatter.ReadObject(stream);

                Console.WriteLine("NetDataContractSerializerFormatter");
                Console.WriteLine(newContact.Address.City);
                Console.WriteLine(newContact.PhoneNumber);
            }
            Console.WriteLine();

            Console.ReadKey();
        }
    }
}
